/**
 * 年历式时间选择器
 * 
 * 1. 使用方法：
 * (1) 需要加载css文件calendar.css
 * 
 * (2) 简单调用：
 * <script language="javascript">
 *	 Calendar.containerId = 'calendar_container_id';	// (必需)要显示到的ID
 *	 Calendar.init();	// 加载
 * </script>
 * 
 * (3) 使用更多设置的调用：
 * <script language="javascript">
 *	 Calendar.containerId = 'calendar_container_id';	// (必需)要显示到的ID
 *	 Calendar.cellWidth = 50;	// 格子宽度 (默认为40)
 *	 Calendar.year = 2011;	// 年设置 (默认为今年)
 *	 Calendar.clickStartTime = 1303660800;	// 开始允许点击的日期 (默认为今天)
 *	 Calendar.readonly = true;	// 是否只读 (默认为false)
 *	 Calendar.data = {'time1301932800' : {value:'清明节', style:'gray', popup:'弹出提示'}, 'time1304179200' : {value:'五一', style:'red'}}; // 填充数据, 目前的可选颜色有gray,green,red,default
 *	 Calendar.inputName = 'selecteddays'; // 提交时的input名称 (默认为selecteddays)
 *	 Calendar.init();	// 加载
 * </script>
 * 
 * (4) 其他：
 * Calendar.setCellWidth(60) 可在运行后设置格子尺寸
 * 
 * @version 1.1.1
 */
var Calendar = {
	
	// ------------------------ // ------------------------
	// 可设置属性
	// ------------------------ // ------------------------
	
	/**
	 * 显示到的容器ID
	 * @var string
	 */
	containerId : '',
	
	/**
	 * Input名称
	 * @var string
	 */
	inputName : 'selecteddays',

	/**
	 * 要设置的年份 (默认为今年)
	 * @var integer
	 */
	year : 0,
	
	/**
	 * 开始允许点击的日期 (默认为今天，如果不用可设置为0)
	 * @var integer
	 */
	clickStartTime : -1,
	
	/**
	 * 日期小块的宽度 (单位px)
	 * @var integer
	 */
	cellWidth : 40,
	
	/**
	 * 是否只读
	 * @var boolen
	 */
	readonly : false,
	
	/**
	 * 是否只允许选择不为空的日期
	 * @var boolen
	 */
	selectNotNull : true,
	
	/**
	 * 在每个点上显示的数据
	 * @var object
	 */
	data : {},
	
	// ------------------------ // ------------------------
	// 内部属性
	// ------------------------ // ------------------------ 
	
	/**
	 * 选中的点
	 * @var object
	 */
	selected : {},
	
	// ------------------------ // ------------------------
	// 初始化
	// ------------------------ // ------------------------ 
	
	/**
	 * 初始化入口
	 */
	init : function() {
		var now = new Date();
		
		// 变量初始化
		this.year = this.year == 0 ? now.getFullYear() : this.year;
		if(this.clickStartTime === -1) {
			this.clickStartTime = (new Date(now.getFullYear(), now.getMonth(), now.getDate())).getTime() / 1000;
		}

		// 基础数据初始化、HTML加载
		this.selectedInit();
		this.htmlInit();
		this.styleInit();
		
		// 事件绑定
		if(!this.readonly) {
			this.monthClick();
			this.weekClick();
			this.weeksequenceClick();
			this.dayClick();
		}
		this.dayMouseover();
		this.dayMouseout();
	},
	
	/**
	 * 动态设置大小 (运行后)
	 * @param integer width
	 */
	setCellWidth : function(width) {
		this.cellWidth = width;
		this.styleInit();
	},
	
	/**
	 * 选中状态数据初始化 (设置this.selected)
	 */
	selectedInit : function() {
		var first = new Date(this.year, 0, 1).getTime() / 1000;
		var last = new Date(this.year, 11, 31).getTime() / 1000;
		for(var i = first; i <= last; i += 86400) {
			this.selected['time' + i] = 0;
		}
	},
	
	/**
	 * HTML初始化
	 */
	htmlInit : function() {
		var html = '';

		// 一年有12个月
		for(var month = 1; month <= 12; month++) {
			html += '<div class="month">';
			html += this.monthtitleHtml(month);
			html += this.weektitleHtml(month);
			html += this.dayHtml(month);
			html += '</div>';
		}
		
		html += '<div id="calendarpopup" class="calendarpopup">正在加载...</div>';
		
		// input加载
		html += this.inputHtml();
		
		$('#' + this.containerId).append(html);
	},
	
	/**
	 * 样式格式化 (高宽)
	 */
	styleInit : function() {
		var shortWidthWrapper = 20;
		var shortWidth = shortWidthWrapper - 1;
		var dayWidth = this.cellWidth - 1;
		var monthWidth = this.cellWidth * 7 + shortWidthWrapper;
		var monthHeight = this.cellWidth * 6 + shortWidthWrapper * 2;
		
		// 整个月
		$('.month').width(monthWidth);
		$('.month').height(monthHeight);
		
		// 月标题
		$('.monthtitle').width(monthWidth - 1);
		$('.monthtitle').height(shortWidth);
		
		// 周标题、周次序交叉点
		$('.weekcross').width(shortWidth);
		$('.weekcross').height(shortWidth);
	
		// 周标题
		$('.weektitle').width(dayWidth);
		$('.weektitle').height(shortWidth);
		
		// 周次序
		$('.weeksequence').width(shortWidth);
		$('.weeksequence').height(dayWidth);
		
		$('.weeksequencenone').width(shortWidth);
		$('.weeksequencenone').height(dayWidth);
		
		// 日期
		$('.day').width(dayWidth);
		$('.day').height(dayWidth);
		$('.day').css('line-height', parseInt(this.cellWidth / 2) + 'px');
		
		$('.daynone').width(dayWidth);
		$('.daynone').height(dayWidth);
	},
	
	// ------------------------ // ------------------------
	// HTML生成
	// ------------------------ // ------------------------ 

	/**
	 * 月标题
	 * @param integer
	 * @return string
	 */
	monthtitleHtml : function(month) {
		var html = '';
		
		html += '<div class="monthtitle" month="' + month + '">' + this.year + '年' + month + ' 月</div>'
	
		return html;
	},
	
	/**
	 * 周标题
	 * @param integer month
	 * @return string
	 */
	weektitleHtml : function(month) {
		var html = '';

		html += '<div class="weekcross"></div>';
		html += '<div class="weektitle" month="' + month + '" week="0">日</div>';
		html += '<div class="weektitle" month="' + month + '" week="1">一</div>';
		html += '<div class="weektitle" month="' + month + '" week="2">二</div>';
		html += '<div class="weektitle" month="' + month + '" week="3">三</div>';
		html += '<div class="weektitle" month="' + month + '" week="4">四</div>';
		html += '<div class="weektitle" month="' + month + '" week="5">五</div>';
		html += '<div class="weektitle" month="' + month + '" week="6">六</div>';
		
		return html;
	},
	
	/**
	 * 日期HTML
	 * @param integer month
	 * @return string
	 */
	dayHtml : function(month) {
		var html = '';
		var day = 0;
		var weeksequence = 0;

		// 开始、结束的格子
		var	date = new Date(this.year, month - 1, 1);
		var start = date.getDay() + 1;
		var startTime = date.getTime() / 1000;
		var date = new Date(this.year, month, 0);
		var end = start + date.getDate() - 1;

		// 一个月需要42个格子
		for(var i = 1; i <= 42; i++) {
			// 显示周次序(第几周)
			if(i % 7 == 1) {
				// 如果是第一行才计算，否则+1
				if(i <= start) {
					var dateStart = new Date(this.year, 0, 0);
					var dateEnd = new Date(this.year, month - 1, 1);
					var weeksequence = Math.ceil(((dateEnd - dateStart) / 86400000 - dateEnd.getDay() - 1) / 7) + 1;
					html += '<div class="weeksequence" month="' + month + '" weeksequence="' + weeksequence + '">' + weeksequence + '</div>';
				} else if (i <= end) {
					weeksequence++;
					html += '<div class="weeksequence" month="' + month + '" weeksequence="' + weeksequence + '">' + weeksequence + '</div>';
				} else {
					html += '<div class="weeksequencenone"></div>';
				}
			}
		
			// 显示日期格子
			if(i >= start && i <= end) {
				day++;
				var timestamp = startTime + (day - 1) * 86400;
				var value = '';
				var style = ' calendardefault';
				var id = 'time' + timestamp;
				var title = value.replace(/<.*?>/g, ''); // title替换HTML标签
				
				// 格子里显示的值value、与样式style
				if(typeof this.data['time' + timestamp] === 'undefined') {
					value = '';
				} else if (typeof this.data['time' + timestamp] === 'object') {
					value = String(this.data['time' + timestamp].value);
					style = typeof this.data['time' + timestamp].style === 'undefined' ? ' calendardefault' : ' calendar' + String(this.data['time' + timestamp].style);
				} else {
					value = String(this.data['time' + timestamp]);
				}
				
				html += '<div class="day' + style + '" day="' + timestamp + '" id="' + id + '" title="' + title + '">';
				html += '<b>' + day + '</b>';
				html += '<span>' + value + '</span>';
				html += '</div>';
			} else {
				html += '<div class="daynone"></div>';
			}
		}
		
		return html;
	},
	
	/**
	 * input表单HTML
	 * @return string
	 */
	inputHtml : function() {
		var html = '';
		
		html += '<input type="hidden" name="' + this.inputName + '" id="' + this.inputName + '" value="" />';
		
		return html;
	},
	
	// ------------------------ // ------------------------
	// 事件绑定
	// ------------------------ // ------------------------ 
	
	/**
	 * 点击月
	 */
	monthClick : function() {
		var self = this;
		$('.monthtitle').click(function() {
			self.toggleMonth($(this).attr('month'));
			self.setInput();
		});
	},
	
	/**
	 * 点击周名
	 */
	weekClick : function() {
		var self = this;
		$('.weektitle').click(function() {
			var month = $(this).attr('month');
			var week = $(this).attr('week');
			self.toggleColumn(month, week);
			self.setInput();
		});
	},
	
	/**
	 * 点击周数
	 */
	weeksequenceClick : function() {
		var self = this;
		$('.weeksequence').click(function() {
			var month = $(this).attr('month');
			var weeksequence = $(this).attr('weeksequence');
			self.toggleWeek(month, weeksequence);
			self.setInput();
		});
	},
	
	/**
	 * 点击天
	 */
	dayClick : function() {
		var self = this;
		$('.day').click(function() {
			var day = $(this).attr('day');
			self.toggleSelect(day);
			self.setInput();
		});
	},
	
	/**
	 * 鼠标移到天上 
	 */
	dayMouseover : function() {
		var self = this;
		$('.day').mouseover(function() {
			var timestamp = $(this).attr('day');
			var popup = '';
			if (typeof self.data['time' + timestamp] !== 'undefined' && typeof self.data['time' + timestamp].popup !== 'undefined') {
				popup = self.data['time' + timestamp].popup;
			}
			
			if (popup !== '') {
				$('#calendarpopup').show();
				$('#calendarpopup').html(popup);
				var offset = $(this).offset();
				var _left = offset.left + 120 > $('body').width() ? offset.left - 120 : offset.left + 2;
				var _top = offset.top + self.cellWidth + 2;
				$('#calendarpopup').offset({ top: _top, left: _left });
			}
		});
	},
	
	/**
	 * 鼠标移开天
	 */
	dayMouseout : function() {
		var self = this;
		$('.day').mouseout(function() {
			$('#calendarpopup').hide();
		});
	},
	
	// ------------------------ // ------------------------
	// 设置Input
	// ------------------------ // ------------------------
	
	/**
	 * 设置Input的值
	 */
	setInput : function() {
		var selected = new Array();
		
		for(i in this.selected) {
			if(this.selected[i] === 1) {
				selected[selected.length] = i.substr(4);
			}
		}
		
		$('#' + this.inputName).val(selected.join(','));
	},
	
	// ------------------------ // ------------------------
	// 扩展选择函数
	// ------------------------ // ------------------------ 
	
	/**
	 * 选择一月(切换效果)
	 * @param integer month
	 */
	toggleMonth : function(month) {
		// 开始结束天
		var first = new Date(this.year, month - 1, 1).getTime() / 1000;
		var last = new Date(this.year, month, 0).getTime() / 1000;
		
		for(var i = first; i <= last; i += 86400) {
			this.toggleSelect(i);
		}
	},
	
	/**
	 * 选择一周(切换效果)
	 * @param integer month
	 * @param integer weeksequence
	 */
	toggleWeek : function(month, weeksequence) {	
		// 本周之前有多少天
		var days = (weeksequence - 2) * 7 + (7 - new Date(this.year, 0, 1).getDay());

		for(var i = 1; i <= 7; i++) {
			var date = new Date(this.year, 0, days + i);

			if(date.getMonth() == month - 1) {
				this.toggleSelect(date.getTime() / 1000);
			}
		}
	},
	
	/**
	 * 选择一列(切换效果)
	 * @param integer month
	 * @param integer week
	 */
	toggleColumn : function(month, week) {
		// 当月最后一天(取下个月的0日)
		var last = new Date(this.year, month, 0).getDate();
		
		for(var i = 1; i <= last; i++) {
			var date = new Date(this.year, month - 1, i);
		
			if(date.getDay() == week) {
				this.toggleSelect(date.getTime() / 1000);
			}
		}
	},
	
	// ------------------------ // ------------------------
	// 基础选择函数
	// ------------------------ // ------------------------
	
	/**
	 * 切换选中一天
	 * @param integer timestamp
	 */
	toggleSelect : function(timestamp) {
		// 没有数据是否允许被选中(不选择空数据日期)
		if(this.selectNotNull && (typeof this.data['time' + timestamp] === 'undefined')) {
			return;
		}
		
		// 是否在开始点击日期之前
		if(timestamp < this.clickStartTime) {
			return;
		}
		
		if(this.selected['time' + timestamp] === 0) {
			this.select(timestamp);
		} else {
			this.unselect(timestamp);
		}
	},
	
	/**
	 * 选中一天
	 * @param integer timestamp
	 */
	select : function(timestamp) {
		$('#time' + timestamp).addClass('selected');
		this.selected['time' + timestamp] = 1;
	},
	
	/**
	 * 反选一天
	 * @param integer timestamp
	 */
	unselect : function(timestamp) {
		$('#time' + timestamp).removeClass('selected');
		this.selected['time' + timestamp] = 0;
	}
	
}
